package org.dromara.xxmj.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.xxmj.config.WechatPayConfig;
import org.dromara.xxmj.domain.dto.WechatRefundPayDTO;
import org.dromara.xxmj.domain.vo.CourseVo;
import org.dromara.xxmj.domain.vo.WechatPayVo;
import org.dromara.xxmj.service.XxmjRegisterService;
import org.dromara.xxmj.utils.SnowFlakeUtil;
import org.dromara.xxmj.utils.WechatUtil;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付管理
 *
 * @author Wangchenfeng
 */
@Slf4j
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping("/wechat")
public class WechatPayController {

    @Resource
    private WechatUtil wechatUtil;

    @Resource
    private XxmjRegisterService registerService;


    /**
     * 微信支付下单
     *
     * @Author 王晨沣 2307105054
     * @Date 2025-05-27 15:07:39
     */
    @Operation(summary = "微信支付下单")
    @RequestMapping("/apiPay")
    public WechatPayVo wechatApiPay(HttpServletRequest request, String courseId) throws Exception {
        String userId = Convert.toStr(LoginHelper.getUserId());

        //获取课程信息
        CourseVo course = registerService.getCourse(courseId);
        Double price = Convert.toDouble(course.getPrice(),999999.99999);
        String description = course.getIntro();
        Double originPrice = Convert.toDouble(course.getOriginalPrice(),999999.99999);
        String merchantID = course.getId() + "_" + course.getCategoryId() + "_" + course.getCreateTime();
        String userIp = request.getRemoteAddr();
        //系统内唯一订单号 雪花算法
        String outTradeNo= Convert.toStr(SnowFlakeUtil.getId());

        Map<String, Object> model = wechatUtil.requestWxPayParam(userId, description, outTradeNo, price, originPrice, merchantID,userIp);
        log.info("统一下单参数 {}", JSONUtil.toJsonStr(model));

        IJPayHttpResponse response = WxPayApi.v3(
            RequestMethodEnum.POST,
            WxDomainEnum.CHINA.toString(),
            BasePayApiEnum.APP_PAY.toString(),
            WechatPayConfig.Mch_ID,
            wechatUtil.getSerialNumber(),
            null,
            WechatPayConfig.certPath,
            JSONUtil.toJsonStr(model));
        log.info("统一下单响应 {}", response);

        WechatPayVo resultVo = new WechatPayVo();
        Map<String, String> map;
        if (response.getStatus() == 200) {
            boolean verifySignature = WxPayKit.verifySignature(response, WechatPayConfig.platformCertPath);
            log.info("verifySignature: {}", verifySignature);
            if (verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                map = WxPayKit.jsApiCreateSign(WechatPayConfig.APP_ID, prepayId,WechatPayConfig.certPath);

                resultVo.setCode(200);
                resultVo.setMessage("下单成功");
                resultVo.setData(map);
                return resultVo;
            }
        }else {
            resultVo.setCode(500);
            resultVo.setMessage("下单失败");
            resultVo.setData(null);
        }
        return resultVo;
    }

    /**
     * 微信支付回调
     * @param request
     * @param response
     */
    @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                WechatPayConfig.Mch_ID, WechatPayConfig.platformCertPath);

            log.info("支付通知明文 {}", plainText);

            if (StrUtil.isNotEmpty(plainText)) {
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 关闭订单
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Operation(summary = "关闭订单")
    @PostMapping("/closeOrder")
    public String closeOrder(@Parameter(description = "订单号") @PathVariable String outTradeNo) throws Exception {
        String url = String.format(WxDomainEnum.CHINA + BasePayApiEnum.CLOSE_ORDER_BY_OUT_TRADE_NO.toString(), outTradeNo);
        log.info("关闭订单url:{}", url);
        Map<String, Object> model = new HashMap<>();
        model.put("mchid", WechatPayConfig.Mch_ID);

        IJPayHttpResponse response = WxPayApi.v3(
            RequestMethodEnum.POST,
            WxDomainEnum.CHINA.toString(),
            url,
            WechatPayConfig.Mch_ID,
            wechatUtil.getSerialNumber(),
            null,
            WechatPayConfig.certPath,
            JSONUtil.toJsonStr(model));

        if (response.getStatus() == 204) {
            //平台证书
            try {
                WxPayKit.verifySignature(response, WechatPayConfig.platformCertPath);
            } catch (Exception e) {
                log.error("微信平台证书更新失败");
            }
            return response.getBody();
        }
        return null;
    }

    @Operation(summary = "退款订单")
    @PostMapping("/refund")
    public String refund(@RequestBody @Valid WechatRefundPayDTO dto) throws Exception {
        String url = String.format(WxDomainEnum.CHINA + BasePayApiEnum.REFUND.toString());

        Map<String, Object> model = new HashMap<>();
        //交易单号(支付的订单号)
        model.put("out_trade_no", dto.getOutTradeNo());
        model.put("out_refund_no", WxPayKit.generateStr());
        Map<String, Object> fee = new HashMap<>();
        //退款（单位：分）
        fee.put("refund", Convert.toInt(Math.round(dto.getRefund() * 100)));
        //订单总额（可发起多笔，最多50笔，详见微信官网）
        fee.put("total",1);
        fee.put("currency","CNY");
        model.put("amount",fee);
        log.info("微信订单退款参数 {}", JSONUtil.toJsonStr(model));

        IJPayHttpResponse response = WxPayApi.v3(
            RequestMethodEnum.POST,
            WxDomainEnum.CHINA.toString(),
            url,
            WechatPayConfig.Mch_ID,
            wechatUtil.getSerialNumber(),
            null,
            WechatPayConfig.certPath,
            JSONUtil.toJsonStr(model)
        );
        log.info("微信订单退款响应 {}", response);
        if (response.getStatus() == 200) {
            WxPayKit.verifySignature(response, WechatPayConfig.platformCertPath);
            return response.getBody();
        } else {
            throw new ServiceException("订单退款响应失败");
        }
    }

    public void callBackRefund(HttpServletRequest request, HttpServletResponse response) {
        log.info("收到微信退款回调");
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            String platformCertPath = WechatPayConfig.platformCertPath;
            String mckKey = WechatPayConfig.apiV3Key;
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,mckKey, platformCertPath);
            log.info("退款通知明文 {}", plainText);
            //逻辑处理

            //回复微信
            if (StrUtil.isNotEmpty(plainText)) {
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("微信回调失败：{}",e.getMessage());
        }
    }



}
